import json
import re

import serial
import serial.tools.list_ports
import threading
import time
import csv
import sys
import pyautogui

WIFI_COM_KEY = "USB-SERIAL CH340"
USB_COM_KEY = "USB 串行设备"

COM_BAUD = 115200
           
# 读取配置文件
cfg_result = {}
with open('configure.json', encoding='utf-8') as json_file:
    cfg_result = json.load(json_file)
    print('configure.json:', cfg_result)



# 串口函数
class Function():
    def __init__(self):

        Function.print_used_com()
        ble_serial = self.get_Serial()
        # self.ble_tx = tx_thread(ble_serial)
        # self.ble_tx.start()
        self.ble_rx = rx_thread(ble_serial)
        self.ble_rx.start()

    def print_used_com( ):
        port_list = list(serial.tools.list_ports.comports())
        if len(port_list) <= 0:
            print("This Serial Port Can not Find!!")
        else:
            print("当前电脑串口有：")
            for i in list(port_list):
                print(i)

    def get_Serial(self, com_name=WIFI_COM_KEY, baud=COM_BAUD):
        serial_com = None

        # 找出所有的串口
        ports = list(serial.tools.list_ports.comports(include_links=False))
        # 打印所有的port
        if not ports:
            print("err: no port")
        else:
            # 查找指定的串口
            result = [s for s in ports if com_name in s.description]
            # print(len(result))
            if len(result) > 1:  # 含有多个串口
                com_num = cfg_result.get('COM')
                result_com = [s for s in ports if com_num in s.description]
                # print(result_com)
                if len(result_com) == 1:
                    print("com find " + com_num)
                    try:
                        open_serial = serial.Serial(com_num, baud)
                        # open_serial.open()
                    except Exception  as e:
                        print("串口打开失败", e)
                        return None

                    return open_serial
                else:
                    print("err: 发现多个串口设备，请在configure.json中进行指定:", com_name)
                    return None

            for port in ports:
                # 查找typec对应的com
                if port.description.find(com_name) != -1:
                    print("com find " + port.name)
                    serial_com = port.name
                    try:
                        open_serial = serial.Serial(serial_com, baud)
                        # open_serial.open()
                    except Exception  as e:
                        print("串口打开失败", e)
                        return None

                    return open_serial
            else:
                # 用户输入的端口不存在
                print("err: 串口不存在，请插入串口设备:", com_name)
                return None

    def int_to_hexbytes(i):
        s = '%X' % i
        if len(s) % 2:
            s = '0' + s
        return [s[i:i + 2] for i in range(0, len(s), 2)]

    def str_to_bytes_str(my_str):
        temp_int = int(my_str)
        temp_list = Function.int_to_hexbytes(temp_int)
        temp_str = "".join(temp_list)
        period_bytes = bytes.fromhex(temp_str)
        return period_bytes

    def parse_string_and_number(s):
        pattern = r'(\w+) (\d+)'
        match = re.search(pattern, s)
        if match:
            string = match.group(1)
            number = int(match.group(2))
            return string, number
        else:
            return None, None

# 根据配置文件和硬件触发进行屏幕动作响应
class PC_action():
    def actin_by_cfg(action, from_ID, cfg_file = 'configure.json'):
        print(action, from_ID)
        cfg_actin = {}
        with open('configure.json', encoding='utf-8') as json_file:
            cfg_actin = json.load(json_file)
            # print('configure.json:', cfg_actin)

        # print(cfg_actin.get('run_mode')["mode"])
        if cfg_actin.get('run_mode')["mode"] == "wheel":  # "run_mode": {"mode": "wheel", "scroll_pixel": 2000, "dir":"down"}
            PC_action.mouse(action, cfg_actin.get('run_mode')["scroll_pixel"], cfg_actin.get('run_mode')["dir"])
        elif cfg_actin.get('run_mode')["mode"] == "button":  # "run_mode": {"mode": "button", "key_name": ""space, "trig_num": 1, "delay_ms": 2000}
            PC_action.button(action, cfg_actin.get('run_mode')["key_name"], cfg_actin.get('run_mode')["trig_num"], cfg_actin.get('run_mode')["delay_ms"])
        else:
            print("其它模式，待开发中")




    def mouse(action, scroll_pixel, dir):  # scroll_pixel 滚动步进
        print(scroll_pixel, dir)
        if dir == "up":
            if action == "long_start":
                pyautogui.scroll(scroll_pixel)
            elif action == "doubleclick":
                pyautogui.scroll(0 - scroll_pixel)

        elif dir == "down":
            if action == "long_start":
                pyautogui.scroll(0-scroll_pixel)
            elif action == "doubleclick":
                pyautogui.scroll(scroll_pixel)

        # time.sleep(5)

    def button(action, key_name, trig_num, time_ms):  # key_name 按键触发名字 trig_num 单次硬件触发按键按下次数 time_ms 触发间隔时间
        print(key_name, trig_num, time_ms)
        if trig_num <= 0:
            trig_num = 1

        for i in range(trig_num):
            print("按下:", key_name)
            if action == "click":
                pyautogui.press(key_name)
            elif action == "doubleclick":
                pyautogui.press(key_name, 2, 0.02)
            elif action == "long_start":
                pyautogui.keyDown(key_name)
            elif action == "long_stop":
                pyautogui.keyUp(key_name)

            if trig_num > 1:
                time.sleep(time_ms * 0.001)





class tx_thread(threading.Thread):  # 发送接收或者发送周期+后1s开始重新发送   发送次数或者时间到了就停止
    def __init__(self, myseial):
        threading.Thread.__init__(self)
        self.serial = myseial
        self.rx_flag = 1
        self.period = ''
        self.pulse = ''

    def run(self):
        print('ble_tx_thread creat')
        key_name = ["AT", "AT+BOND", "AT+MAC"]

        num = 0
        while True:
            num = num + 1
            if num >= self.max_tx_period * 0.1 or self.rx_flag == 1:
                num = 0
                self.rx_flag = 0

                send_str = str(key_num)
                send_str += ' '
                send_str += self.period
                send_str += ' '
                send_str += self.pulse
                send_str += ' '
                print('test tx data is:', key_name[key_num % 3], send_str)

                self.serial.write(send_str.encode())

            time.sleep(0.01)


class rx_thread(threading.Thread):
    def __init__(self, myseial):
        threading.Thread.__init__(self)
        self.serial = myseial

    def run(self):
        print('ble_rx_thread creat')
        while 1:
            try:
                if self.serial.isOpen():
                    n = self.serial.inWaiting()
                    if n:
                        time.sleep(0.001)
                        n = self.serial.inWaiting()

                        data = self.serial.read(n)
                        ib = []
                        for tb in data:
                            if 13 != tb:
                                ib.append(tb)
                        data = bytes(ib).decode()
                        # print(data)

                        if data != '':
                            # print('串口接收数据：', data)
                            # print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
                            self.rx_data = data
                            string, number = Function.parse_string_and_number(self.rx_data)
                            if string != None and number != None:
                                # print("检测到硬件触发关键词")
                                PC_action.actin_by_cfg(string, number)
                    else:
                        time.sleep(0.1)
            except:
                print("串口异常，正在尝试重新连接···")
                time.sleep(1)
                self.serial = ble_con.get_Serial(WIFI_COM_KEY)
                if self.serial == None:  # 在有线和无线之间进行切换尝试
                    self.serial = ble_con.get_Serial(USB_COM_KEY)




if __name__ == '__main__':
    ble_con = Function()
    # PC_action.actin_by_cfg()
    pass